﻿using System;
using System.IO;

namespace Narwhunderful.Aphelia.Framework.IO.Serialization.Binary
{

    public static class BinaryWriterHelpers
    {

        public static void WriteNumber(int number, BinaryWriter writer)
        {
            // Write size
            byte size = NumberSize.GetNumberSize(number);
            writer.Write(size);

            // Write number
            if (size > NumberSize.Zero)
            {
                switch (size)
                {
                    case NumberSize.B1:
                        writer.Write((byte)number);
                        break;
                    case NumberSize.B2:
                        writer.Write((Int16)number);
                        break;
                    default:
                        writer.Write(number);
                        break;
                }
            }
        }

        public static void WriteNumbers(int[] numbers, BinaryWriter writer)
        {
            // Length
            WriteNumber(numbers.Length, writer);

            // Numbers
            foreach (int number in numbers)
            {
                WriteNumber(number, writer);
            }
        }

        public static void WriteValue(object value, BinaryWriter writer)
        {
            if (value == null)
            {
                writer.Write(false);
            }
            else
            {
                writer.Write(true);
                WriteValueCore(value, writer);
            }
        }

        public static void WriteString(string text, BinaryWriter writer)
        {
            if (string.IsNullOrEmpty(text))
            {
                // no exception if the text is null
                writer.Write(false);
            }
            else
            {
                writer.Write(true);
                writer.Write(text);
            }
        }

        private static void WriteValueCore(object value, BinaryWriter writer)
        {
            if (value == null) throw new ArgumentNullException("value", "Written data can not be null.");

            // Write argument data
            Type type = value.GetType();

            if (type == typeof(byte[]))
            {
                WriteArrayOfByte((byte[])value, writer);
                return;
            }
            if (type == typeof(string))
            {
                writer.Write((string)value);
                return;
            }
            if (type == typeof(Boolean))
            {
                writer.Write((bool)value);
                return;
            }
            if (type == typeof(Byte))
            {
                writer.Write((byte)value);
                return;
            }
            if (type == typeof(Char))
            {
                writer.Write((Char)value);
                return;
            }
            if (type == typeof(DateTime))
            {
                writer.Write(((DateTime)value).Ticks);
                return;
            }
            if (type == typeof(Guid))
            {
                writer.Write(((Guid)value).ToByteArray());
                return;
            }
#if (SMARTPHONE || SILVERLIGHT || XBOX)
#else
            if (type == typeof(Decimal))
            {
                writer.Write((Decimal)value);
                return;
            }
#endif
            if (type == typeof(Double))
            {
                writer.Write((Double)value);
                return;
            }
            if (type == typeof(Int16))
            {
                writer.Write((Int16)value);
                return;
            }
            if (type == typeof(Int32))
            {
                writer.Write((Int32)value);
                return;
            }
            if (type == typeof(Int64))
            {
                writer.Write((Int64)value);
                return;
            }
            if (type == typeof(SByte))
            {
                writer.Write((SByte)value);
                return;
            }
            if (type == typeof(Single))
            {
                writer.Write((Single)value);
                return;
            }
            if (type == typeof(UInt16))
            {
                writer.Write((UInt16)value);
                return;
            }
            if (type == typeof(UInt32))
            {
                writer.Write((UInt32)value);
                return;
            }
            if (type == typeof(UInt64))
            {
                writer.Write((UInt64)value);
                return;
            }

            if (type == typeof(TimeSpan))
            {
                writer.Write(((TimeSpan)value).Ticks);
                return;
            }

            // Enumeration
            if (type.IsEnum)
            {
                writer.Write((int)value);
                return;
            }

            throw new InvalidOperationException(string.Format("Unknown simple type: {0}", type.FullName));
        }

        private static void WriteArrayOfByte(byte[] data, BinaryWriter writer)
        {
            WriteNumber(data.Length, writer);
            writer.Write(data);
        }
    }
}
